package com.gitee.cui.nio.reactor;

import com.gitee.cui.nio.NioDemoConfig;
import com.gitee.cui.util.Logger;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 打印回显处理类，是一个线程，引入多线程机制，避免单线程处理业务逻辑时阻塞问题
 * @author cuiqingqiang
 * @version 1.0
 * @date 2021/10/20 13:44
 **/
public class MultiThreadEchoHandler implements Runnable {

    /**
     * 连接通道
     */
    private SocketChannel channel;

    /**
     * 注册到selector的selectionkey
     */
    private SelectionKey selectionKey;

    /**
     * 定义缓冲区
     */
    private static final ByteBuffer BUFFER = ByteBuffer.allocate(NioDemoConfig.SEND_BUFFER_SIZE);

    /**
     * 创建一个有4个线程的线程池
     */
    private static final ExecutorService pool = Executors.newFixedThreadPool(4);

    /**
     * 定义的读取，发送状态
     */
    private static final int RECEIVE = 0, SENDING = 1;

    /**
     * 状态码，根据状态进行读写操作
     */
    private int state = RECEIVE;

    public MultiThreadEchoHandler(Selector selector, SocketChannel socketChannel) throws IOException {
        channel = socketChannel;
        // 设置为异步处理通道
        channel.configureBlocking(false);
        // 注册通道到选择器，只关心返回的selectionkey
        selectionKey = channel.register(selector, 0);
        // 将当前处理类，作为附件添加到selectionKey中
        selectionKey.attach(this);
        // 设置感兴趣的监听事件
        selectionKey.interestOps(SelectionKey.OP_READ);
        selector.wakeup();
    }

    @Override
    public void run() {
        pool.execute(new AsyncTask());
    }

    private synchronized void asyncRun() {
        try {
            if (state == SENDING) {
                // 将数据写道通道中，此时buffer为读状态
                channel.write(BUFFER);
                // 将buffer置为可写状态
                BUFFER.clear();
                // 设置selectionkey的监听事件为读事件
                selectionKey.interestOps(SelectionKey.OP_READ);
                // 修改状态为接受内容
                state = RECEIVE;
            } else if (state == RECEIVE) {
                // 从通道中读取数据
                int length = 0;
                while ((length = channel.read(BUFFER)) > 0) {
                    Logger.info(new String(BUFFER.array(), 0, length));
                }
                // 将buffer置为可读
                BUFFER.flip();
                // 设置selectionkey的监听事件为写事件
                selectionKey.interestOps(SelectionKey.OP_WRITE);
                state = SENDING;
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    class AsyncTask implements Runnable {

        @Override
        public void run() {
            MultiThreadEchoHandler.this.asyncRun();
        }
    }
}
